#[post("/library/copywrite_file_upload", data = "<data>")]
fn copywrite_file_upload(cookies: Cookies, data: Data) -> String {
    let user_info: UserInfo = get_cookies(&cookies);
    if user_info.id == 0 {
        return "fail:您未登录，请先登录".to_string();
    }

    let mut file_hostr: HoString = HoString::new();
    file_hostr.push_bytes(data.peek());
    let file_info: Vec<HoString> = file_hostr.split_bytes("\n".as_bytes());
    let file_name_op: Option<&HoString> = file_info.get(7);
    let mut file_name: HoString = HoString::new();
    if let Some(f) = file_name_op {
        let file_name_u8: &[u8] = f.trim();
        file_name.push_bytes(file_name_u8);
    } else {
        return "fail:Data数据不合法".to_string();
    }
    let file_name_array: Vec<HoString> = file_name.split_bytes(".".as_bytes());
    let file_name_array_len: usize = file_name_array.len() - 1;
    let file_extra_name: &HoString = file_name_array.get(file_name_array_len).unwrap();
    let now: SystemTime = SystemTime::now();
    let since_epoch_res = now.duration_since(UNIX_EPOCH);
    let since_epoch: Duration;
    if let Ok(d) = since_epoch_res {
        since_epoch = d;
    } else {
        return "fail:时间戳获取失败".to_string();
    }
    let timestamp = since_epoch.as_millis();
    let upload_name: String = format!("uploads/{}.{}", timestamp, file_extra_name.to_str());
    if let Ok(_) = data.stream_to_file(upload_name.as_str()) {
        let u8_vec: Vec<u8> = HoFile::read_file_u8vec(upload_name.as_str());
        let mut bytes: HoBytes = HoBytes::new();
        bytes.push_bytes(u8_vec.as_slice());
        let u8_vec_vec: Vec<Vec<u8>> = bytes.split_byte('\n' as u8);
        let mut content: HoBytes = HoBytes::new();
        for i in 24..u8_vec_vec.len() - 1 {
            match u8_vec_vec.get(i) {
                Some(v) => content.push_bytes(v.as_slice()),
                None => break
            }
        }
        HoFile::write_file_bytes(upload_name.as_str(), content.to_bytes());
        return format!("success:{}.{}", timestamp, file_extra_name.to_str());
    } else {
        return "fail:文件移动失败".to_string();
    }
}

#[derive(FromForm)]
struct TaskUpdate {
    id: usize,
    remove_file_list: String,
    file_list: String,
    title: String
}

#[post("/library/upload_task_order", data = "<topic>")]
fn upload_task_order(topic: Form<TaskUpdate>, cookies: Cookies, state: State<MySqlDriver>) -> String {
    let title_len = topic.title.chars().count();
    let title_hostr: HoString = HoString::copy_string(topic.title.clone());
    let title_segment_vec: Vec<HoString> = title_hostr.split_bytes("，".as_bytes());
    if title_segment_vec.len() != 3 || title_len > 30 || title_len < 26 {
        return "fail:标题长度必须在26到30个之间，且必须为三段式，用中文逗号分隔".to_string();
    }

    let user_info: UserInfo = get_cookies(&cookies);
    let user_id: usize = user_info.id;

    let mut except_vec: Vec<char> = Vec::new();
    except_vec.push('\'');
    except_vec.push('"');
    except_vec.push('\\');
    let remove_file_list_hostr: HoString = HoString::copy_string(topic.remove_file_list.clone());
    let file_list_hostr: HoString = HoString::copy_string(topic.file_list.clone());
    let title_hostr: HoString = HoString::copy_string(topic.title.clone());
    if title_hostr.length() == 0 {
        return "fail:表单不能有空".to_string();
    }
    if remove_file_list_hostr.contains_char_vec(except_vec.clone(), 0) == true ||
        file_list_hostr.contains_char_vec(except_vec.clone(), 0) == true ||
        title_hostr.contains_char_vec(except_vec.clone(), 0) == true {
        return "fail:表单值不能包含引号和斜杠".to_string();
    }

    let remove_file_array: Vec<HoString> = remove_file_list_hostr.split_str("|");
    let file_array: Vec<HoString> = file_list_hostr.split_str("|");
    for remove_file_item in remove_file_array {
        let _ = remove_file(format!("uploads/{}", remove_file_item.to_str()).as_str());
    }

    let now: SystemTime = SystemTime::now();
    let since_epoch_res = now.duration_since(UNIX_EPOCH);
    let since_epoch: Duration;
    if let Ok(d) = since_epoch_res {
        since_epoch = d;
    } else {
        return "fail:时间戳获取失败".to_string();
    }
    let timestamp = since_epoch.as_millis();

    let pool_result: Result<Pool, mysql::Error> = Pool::new(state.driver.as_str());
    let pool: Pool;
    if let Ok(p) = pool_result {
        pool = p;
    } else {
        return "fail:无法建立数据库连接".to_string();
    }
    let conn_result: Result<PooledConn, mysql::Error> = pool.get_conn();
    let mut conn: PooledConn;
    if let Ok(c) = conn_result {
        conn = c;
    } else {
        return "fail:无法获取数据库连接".to_string();
    }

    let mut sql: String = format!("SELECT `get_user_id` FROM `copywrite_order` WHERE `id` = '{}' LIMIT 1", topic.id);
    let row: Row = conn.query_first(sql.as_str()).unwrap().unwrap();
    let get_user_id: usize = from_row(row);
    if get_user_id != user_id {
        return "fail:您未接该订单".to_string();
    }

    let secs = since_epoch.as_secs();
    let tar_file: File;
    let gz_file: String = format!("{}.tar", timestamp);
    if let Ok(f) = File::create(format!("uploads/{}.tar", timestamp).as_str()) {
        tar_file = f;
    } else {
        return "fail:压缩包创建失败".to_string();
    }
    let mut tar_new = Builder::new(tar_file);
    for file_item in file_array {
        let mut open_item: File;
        if let Ok(f) = File::open(format!("uploads/{}", file_item.to_str()).as_str()) {
            open_item = f;
        } else {
            return format!("fail:{}打开失败", file_item.to_str());
        }
        if let Err(_) = tar_new.append_file(format!("{}/{}", timestamp, file_item.to_str()).as_str(), &mut open_item) {
            return format!("fail:{}压缩失败", file_item.to_str());
        }
    }

    let files_string: String = format!("{}|{}", gz_file.as_str(), file_list_hostr.to_str());
    sql = "UPDATE `copywrite_order` SET `word_file` = :zip_name, `status` = 2, `update_datetime` = :time, `title` = :title WHERE `id` = :id".to_string();
    let _ = conn.exec_drop(sql.clone(), params![
        "zip_name" => files_string.as_str(),
        "time" => secs,
        "title" => topic.title.as_str(),
        "id" => topic.id
    ]);
    
    return "success:".to_string();
}

#[get("/view_copywrite_task?<id>")]
fn view_copywrite_task(id: usize, cookies: Cookies, state: State<MySqlDriver>) -> Response<'static> {
    let mut res = Response::new();
    res.set_header(ContentType::HTML);
    let user_info: UserInfo = get_cookies(&cookies);
    if user_info.id == 0 {
        let info: String = format!("您未登录，请先<a href=\"{}login\">登录</a>", state.base_url.as_str());
        res.set_sized_body(Cursor::new(info));
        return res;
    }

    // mod_id: String, 
    // mod_menu_open: String, 
    // sub_mod_id: String, 
    // page_title: String, 
    // title: String
    let header: String = get_header(
        "task-mod".to_string(), 
        "task-mod-menu-open".to_string(), 
        String::new(),
        "用户后台 - 订单任务".to_string(), 
        "订单任务".to_string(), &cookies,
        &state);

    let pool_result: Result<Pool, mysql::Error> = Pool::new(state.driver.as_str());
    let pool: Pool;
    if let Ok(p) = pool_result {
        pool = p;
    } else {
        res.set_sized_body(Cursor::new("无法建立数据库连接".to_string()));
        return res;
    }
    let conn_result: Result<PooledConn, mysql::Error> = pool.get_conn();
    let mut conn: PooledConn;
    if let Ok(c) = conn_result {
        conn = c;
    } else {
        res.set_sized_body(Cursor::new("无法获取数据库连接".to_string()));
        return res;
    }

    let sql: String = format!("SELECT `copy_o`.`title`, `copy_o`.`requirement`, `copy_o`.`word_file`, `copy_o`.`refuse_reason`, `copy_o`.`group_id` FROM `copywrite_order` AS `copy_o` INNER JOIN `topic` AS `t` ON `t`.`id` = `copy_o`.`topic_id` INNER JOIN `tag_group` AS `tg` ON `tg`.`id` = `copy_o`.`group_id` WHERE `copy_o`.`id` = {} LIMIT 1", id);
    let row_op: Option<Row> = conn.query_first(sql.as_str()).unwrap();
    let row: Row;
    if let Some(r) = row_op {
        row = r;
    } else {
        res.set_sized_body(Cursor::new("找不到该订单".to_string()));
        return res;
    }

    let (title, requirement, word_file, refuse_reason, group_id): (String, String, String, String, usize) = from_row(row);
    let mut word_file_first: HoString = HoString::new();
    let mut word_file_html: String = String::new();
    if word_file.len() != 0 {
        let word_file_hostr: HoString = HoString::copy_string(word_file.clone());
        let mut word_file_array: Vec<HoString> = word_file_hostr.split_str("|");
        word_file_first = word_file_array.remove(0);
        let mut index: usize = 0;
        for word_file_item in word_file_array {
            if word_file_item.length() == 0 {
                continue;
            }
            word_file_html.push_str(format!("<li class=\"list-group-item d-flex justify-content-between align-items-center\" id=\"file{}\">\
                                                <a target=\"_blank\" href=\"{}uploads/{}\" download=\"{}\">{}</a>\
                                                <span class=\"badge badge-success badge-pill\">已上传</span>\
                                                <button type=\"button\" class=\"badge badge-danger badge-pill\" onclick=\"remove_file(0, '{}', 'file{}')\">删除</button>\
                                            </li>", index, state.base_url.as_str(), word_file_item.to_str(), word_file_item.to_str(), word_file_item.to_str(), word_file_item.to_str(), index).as_str());
            index += 1;
        }
    }

    let mut src_vec: Vec<&[u8]> = Vec::new();
    let mut replace_vec: Vec<&[u8]> = Vec::new();

    let id_str: String = id.to_string();
    let group_id_str: String = group_id.to_string();
    let user_id_str: String = user_info.id.to_string();
    let footer_string: String = get_footer();
    src_vec.push("{header}".as_bytes());
    src_vec.push("{id}".as_bytes());
    src_vec.push("{base_url}".as_bytes());
    src_vec.push("{title}".as_bytes());
    src_vec.push("{requirement}".as_bytes());
    src_vec.push("{refuse_reason}".as_bytes());
    src_vec.push("{group_id}".as_bytes());
    src_vec.push("{uid}".as_bytes());
    src_vec.push("{first}".as_bytes());
    src_vec.push("{word_file}".as_bytes());
    src_vec.push("{footer}".as_bytes());
    replace_vec.push(header.as_bytes());
    replace_vec.push(id_str.as_bytes());
    replace_vec.push(state.base_url.as_bytes());
    replace_vec.push(title.as_bytes());
    replace_vec.push(requirement.as_bytes());
    replace_vec.push(refuse_reason.as_bytes());
    replace_vec.push(group_id_str.as_bytes());
    replace_vec.push(user_id_str.as_bytes());
    replace_vec.push(word_file_first.to_bytes());
    replace_vec.push(word_file_html.as_bytes());
    replace_vec.push(footer_string.as_bytes());

    let mut page_str: HoString = HoFile::read_file_bytes("web/view_copywrite_task.html");
    page_str = page_str.replace_bytes_vec(src_vec, replace_vec);
    let html: String = page_str.to_str().to_string().to_owned();
    res.set_sized_body(Cursor::new(html));
    return res;
}

#[get("/view_clip_task?<id>")]
fn view_clip_task(id: usize, cookies: Cookies, state: State<MySqlDriver>) -> Response<'static> {
    let mut res = Response::new();
    res.set_header(ContentType::HTML);
    let user_info: UserInfo = get_cookies(&cookies);
    if user_info.id == 0 {
        let info: String = format!("您未登录，请先<a href=\"{}login\">登录</a>", state.base_url.as_str());
        res.set_sized_body(Cursor::new(info));
        return res;
    }

    // mod_id: String, 
    // mod_menu_open: String, 
    // sub_mod_id: String, 
    // page_title: String, 
    // title: String
    let header: String = get_header(
        "task-mod".to_string(), 
        "task-mod-menu-open".to_string(), 
        String::new(),
        "用户后台 - 订单任务".to_string(), 
        "订单任务".to_string(), &cookies,
        &state);

    let pool_result: Result<Pool, mysql::Error> = Pool::new(state.driver.as_str());
    let pool: Pool;
    if let Ok(p) = pool_result {
        pool = p;
    } else {
        res.set_sized_body(Cursor::new("无法建立数据库连接".to_string()));
        return res;
    }
    let conn_result: Result<PooledConn, mysql::Error> = pool.get_conn();
    let mut conn: PooledConn;
    if let Ok(c) = conn_result {
        conn = c;
    } else {
        res.set_sized_body(Cursor::new("无法获取数据库连接".to_string()));
        return res;
    }

    let mut sql: String = "SELECT `global_value` AS `clip_requirement` FROM `global_var` WHERE `global_key` = 'clip_requirement' LIMIT 1".to_string();
    let row_op: Option<Row> = conn.query_first(sql.as_str()).unwrap();
    let row: Row;
    if let Some(r) = row_op {
        row = r;
    } else {
        res.set_sized_body(Cursor::new("无法查询剪辑要求".to_string()));
        return res;
    }
    let clip_requirement: String = from_row(row);

    sql = format!("SELECT `copy_o`.`title` FROM `clip_order` AS `clip_o` INNER JOIN `copywrite_order` AS `copy_o` ON `copy_o`.`id` = `clip_o`.`copywrite_id` WHERE `clip_o`.`id` = {} LIMIT 1", id);
    let row_op: Option<Row> = conn.query_first(sql.as_str()).unwrap();
    let row: Row;
    if let Some(r) = row_op {
        row = r;
    } else {
        res.set_sized_body(Cursor::new("找不到该订单".to_string()));
        return res;
    }
    let title: String = from_row(row);

    let mut src_vec: Vec<&[u8]> = Vec::new();
    let mut replace_vec: Vec<&[u8]> = Vec::new();

    let id_str: String = id.to_string();
    let footer_string: String = get_footer();
    src_vec.push("{header}".as_bytes());
    src_vec.push("{id}".as_bytes());
    src_vec.push("{base_url}".as_bytes());
    src_vec.push("{title}".as_bytes());
    src_vec.push("{clip_requirement}".as_bytes());
    src_vec.push("{footer}".as_bytes());
    replace_vec.push(header.as_bytes());
    replace_vec.push(id_str.as_bytes());
    replace_vec.push(state.base_url.as_bytes());
    replace_vec.push(title.as_bytes());
    replace_vec.push(clip_requirement.as_bytes());
    replace_vec.push(footer_string.as_bytes());

    let mut page_str: HoString = HoFile::read_file_bytes("web/view_clip_task.html");
    page_str = page_str.replace_bytes_vec(src_vec, replace_vec);
    let html: String = page_str.to_str().to_string().to_owned();
    res.set_sized_body(Cursor::new(html));
    return res;
}

